/*
 * pps_pll_hal.c
 *
 *  Created on: 17 juin 2014
 *      Author: marioc
 */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>

#include "bsp/system.h"		// do not use bsp in target
//#include "altera_avalon_sysid_qsys.h"
//#include "altera_avalon_sysid_qsys_regs.h"

#include "hal/pps_pll_hal.h"
//#include "hal/platform_defines.h"
//#include "hal/sysconf_hal.h"
#include "hal/register.h"
//#include "hal/avalon_hal.h"
//#include "hal/enet_hal.h"
//#include "hal/net_address_hal.h"


#include "hcpp/ptp2_log.h"


#define NS_PER_CYCLE    (8)

void
pps_pll_hal_init(uint32_t pps_width)
{

    uint32_t  tmp  = av_bus_read_32(HOST_PULSE_WIDTH);
    tmp |= (pps_width & 0x3FFFFFFF);
    av_bus_write_32(HOST_PULSE_WIDTH, tmp);
}


/**
 * @brief   retrieve the delta phase PPSref - PPSgen in steps of 8ns
 *
 * @param   ref: phase
 */
void
pps_pll_phase_get(int32_t *phase)
{
    *phase  = av_bus_read_32(HOST_PHASE_MEAS);

}

void
pps_pll_phase_set(int32_t value)
{
    av_bus_write_32(HOST_PHASE_MEAS, value);

}


/**
 * @brief   retrieve the period duration of the PPS PLL. Value is returned in number of clock steps each of 8ns .
 *
 * @param   ref: phase
 */
void
pps_pll_period_get(uint32_t *correction)
{
    *correction  = ((av_bus_read_32(HOST_PLL_PPS_Status) >> 4) & 0x1FFFFFFF);
}

void
pps_pll_limits_get(uint32_t *lim_tmax, uint32_t *lim_tmin)
{
    *lim_tmax  = (av_bus_read_32(HOST_LimTmax) & 0xFFFFFFF) * NS_PER_CYCLE;
    *lim_tmin  = (av_bus_read_32(HOST_LimTmin) & 0xFFFFFFF) * NS_PER_CYCLE;

}

typedef struct {
    uint16_t    fract_part : 8;
    uint16_t    int_part : 3;
    uint16_t    sign : 1;
    uint16_t    padding : 4;
} regulator_reg_t;


typedef union {
    uint32_t    raw_reg;
    struct {
        union  {
            uint16_t        raw_kp;
            regulator_reg_t reg_kp;
        } kp;
        union  {
            uint16_t        raw_ki;
            regulator_reg_t reg_ki;
        } ki;

    } reg_t;
} regulator_param_t;

void
pps_pll_filter_get(float *ki, float *kp, uint8_t filter_num)
{
    regulator_param_t   regulator_a;
    uint16_t            fract_part;
    int16_t             int_part;
    uint32_t            address = (filter_num == 0) ? HOST_KxA : HOST_KxB;


    regulator_a.raw_reg = av_bus_read_32(address);

    fract_part = regulator_a.reg_t.kp.reg_kp.fract_part;
    if (regulator_a.reg_t.kp.reg_kp.sign == 0) {
        int_part = regulator_a.reg_t.kp.reg_kp.int_part;
    }
    else {
        int_part = regulator_a.reg_t.kp.reg_kp.int_part - 8;
    }
    *kp = int_part + (fract_part/256.0);


    fract_part = regulator_a.reg_t.ki.reg_ki.fract_part;
    if (regulator_a.reg_t.ki.reg_ki.sign == 0) {
        int_part = regulator_a.reg_t.ki.reg_ki.int_part;
    }
    else {
        int_part = regulator_a.reg_t.ki.reg_ki.int_part - 8;
    }

    *ki = int_part + ((float)fract_part)/256.0;


}


void
pps_pll_accumulator_get(uint32_t *accumulator)
{
    *accumulator = av_bus_read_32(HOST_Accu) & 0xFFFFFFF;
}


void
pps_pll_resync(void)
{
    uint32_t tmp = av_bus_read_32(HOST_PLL_CTRL);
    tmp |= RSYNC;
    av_bus_write_32(HOST_PLL_CTRL, tmp);
}

void
pps_pll_status_reg_get  (host_pll_pps_status_t *reg)
{
    reg->raw = av_bus_read_32(HOST_PLL_PPS_Status);
}

void
pps_pll_ctrl_reg_get(host_pll_pps_ctrl_t *reg)
{
    reg->raw = av_bus_read_32(HOST_PLL_CTRL);
}

void
pps_pll_status_reg_set  (uint32_t value)
{
    av_bus_write_32(HOST_PLL_PPS_Status, value);
}

void
pps_pll_control_reg_set  (uint32_t value)
{
    av_bus_write_32(HOST_PLL_CTRL, value);
}

